﻿/*
 * 通用函数类
 * Created By Zeus2
 * 
 * Last Updated ON 2008-11-22
 * 2008-11-22：
 *      注入检测采用正则表达式，提高准确率，降低误杀率。
 * 
 */

using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Text.RegularExpressions;
namespace HZ
{
    /// <summary>
    /// 常用的函数如安全检查，16进制转换，类型转换等等。
    /// </summary>
    public static class Fun2
    {
        /// <summary>
        /// 检查字符串是否有SQL注入倾向。
        /// </summary>
        /// <param name="input">用户输入的字符串</param>
        /// <returns>true表示可能注入,false表示该字符串安全</returns>
        /// <example>
        /// 代码示例
        /// <code>
        /// // 下面语句将返回true
        ///  bool r1 = HZ.Fun.MaySqlInject("exec sp_execsql"); // 检测是否带有sql语句
        /// </code>
        /// </example>
        public static bool MaySqlInject(string input)
        {

            Regex regex = new Regex(@"exec|insert|select|delete|drop|alter|update |declare|cast|convert|create|<script|<iframe|backup|char.*\(.+\)", RegexOptions.IgnoreCase);
            if (regex.IsMatch(input.Replace("mso-char-indent-count", "")))
            {
                return true;
            }
            else //检查char
            {
                ////  "mso-char-indent-count"  Word文档粘贴
                //Regex regex1 = new Regex("mso-char-indent-count", RegexOptions.IgnoreCase);
                //Regex regex2 = new Regex("char", RegexOptions.IgnoreCase);
                //if (regex1.Matches(input).Count == regex2.Matches(input).Count)
                // 如果查到的char全是mso-char-indent-count，则可以肯定是文本编辑器提交，放过过滤。
                // 解决文本编辑器char问题
                return false;
                //else
                //    return true;
            }
        }
        /// <summary>
        /// 检查用户输入，如果可能SQL注入或者空字符串返回""。
        /// </summary>
        /// <param name="s">用户输入字符串</param>
        /// <returns>过滤后的字符串</returns>
        /// <remarks>
        /// 若obj为空或者含有危险字符则返回string.Empty
        /// </remarks>
        /// <example>
        /// 举例
        /// <code>
        /// string s = "SELECT * FROM ABC";
        /// s = HZ.Fun.CheckString(s);
        /// // s 为 string.Empty
        /// </code>
        /// 
        /// </example>
        public static string CheckString(string s)
        {
            if (s == null || MaySqlInject(s))
            {
                return string.Empty;
            }
            else
            {
                return s;
            }
        }
        /// <summary>
        /// 对传入数据进行过滤的object转换为stirng的方法
        /// </summary>
        /// <param name="obj">传入的输入对象</param>
        /// <returns>经过过滤的对象</returns>
        /// <remarks>
        /// 若obj为空或者含有危险字符则返回string.Empty
        /// </remarks>
        [Obsolete("该方法已过期，请使用ConvertUtil代替")]
        public static string ObjToStrA(object obj)
        {
            if (obj == null)
            {
                return "";
            }
            string s = obj.ToString();
            if (MaySqlInject(s))
            {
                return "";
            }
            else
            {
                s.Replace("'", ""); // Excel表格中常用字符串',应过滤
                return s;
            }
        }

        /// <summary>
        /// 将对象转换为字符串，防止出现null转换为string的情况。
        /// </summary>
        /// <param name="obj">带转换的对象</param>
        /// <returns>对象重载的ToString方法</returns>
        /// <remarks>
        /// 当对象为空时
        /// 返回string.Empty
        /// </remarks>
        [Obsolete("该方法已过期，请使用ConvertUtil代替")]
        public static string ObjToStr(object obj)
        {
            if (obj == null)
            {
                return "";
            }
            else
            {
                return obj.ToString();
            }
        }

        /// <summary>
        /// 获取客户端IP。如内网访问格式为***.***.***.***:***.***.***.***
        /// 使用仅为ASP.NET。
        /// </summary>
        /// <remarks>
        /// 若客户端直接连接服务器，获取客户端外网地址___.___.___.___格式。
        /// 若客户端采用代理连接服务器，获取的客户端外网地址为___.___.___.___:___.___.___.___格式。
        /// 若用户采用多级代理依次向后。
        /// 
        /// 存储IP地址时，建议采用varchar(255)存储
        /// </remarks>
        /// <example>
        /// 举例
        /// <code>
        /// string clientipaddress = HZ.Fun.GetClientIP();
        /// // 若本地访问返回127.0.0.1
        /// </code>
        /// </example>
        public static string GetClientIP()
        {
            string uip = GetClientIPViaProxy();
            if (string.IsNullOrEmpty(uip))
            {
                return HttpContext.Current.Request.UserHostAddress;
            }
            else
                return HttpContext.Current.Request.UserHostAddress + ":" + GetClientIPViaProxy();
        }

        private static string GetClientIPViaProxy()
        {
            // string uip = "";

            // return Fun.ObjToStr(HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]); // 这样就可以了。
            return (new HZ.Common.ConvertHelper(HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"])).String;
            //if (HttpContext.Current.Request.ServerVariables["HTTP_VIA"] != null)
            //{
            //    uip = Fun.ObjToStr(HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]);
            //}
            //else
            //{
            //    uip = Fun.ObjToStr(HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"]);
            //}
            //if (MaySqlInject(uip) || string.IsNullOrEmpty(uip))
            //{
            //    return "";
            //}
            //else
            //{
            //    return uip;
            //}
        }

        /// <summary>
        /// 过滤用户输入的危险html字符
        /// </summary>
        /// <param name="text">用户输入的字符串</param>
        /// <param name="maxLength">用户输入的字符串最大长度</param>
        /// <returns>清楚后的用户输入字符串</returns>
        /// <example>
        /// 举例
        /// <code>
        /// string input = "<b>UserInfo</b>";
        /// input = HZ.Fun.InputText(input,4096);
        /// // input为UserInfo
        /// </code>
        /// 
        /// </example>
        public static string InputText(string text, int maxLength)
        {
            text = text.Trim();
            if (string.IsNullOrEmpty(text))
                return string.Empty;
            if (text.Length > maxLength)
                text = text.Substring(0, maxLength);
            text = Regex.Replace(text, "[\\s]{2,}", " ");	//two or more spaces
            text = Regex.Replace(text, "(<[b|B][r|R]/*>)+|(<[p|P](.|\\n)*?>)", "\n");	//<br>
            text = Regex.Replace(text, "(\\s*&[n|N][b|B][s|S][p|P];\\s*)+", " ");	//&nbsp;
            text = Regex.Replace(text, "<(.|\\n)*?>", string.Empty);	//any other tags
            text = text.Replace("'", "''");
            return text;
        }
        /// <summary>
        /// 计算给定字符串的哈希值
        /// </summary>
        /// <param name="src">待计算的字符串</param>
        /// <returns>计算后的哈希值</returns>
        /// <remarks>
        /// 当字符串传入null或者string.Empty时，返回string.Empty
        /// </remarks>
        /// <example>
        /// 举例说明
        /// <code>
        /// string r11 = HZ.Fun.GetMd5("pwd");
        /// </code>
        /// </example>
        public static string GetMd5(string src)
        {
            if (string.IsNullOrEmpty(src))
            {
                return string.Empty;
            }
            else
            {
                string tmp = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(src, "SHA1");
                return System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(tmp, "MD5");
            }
        }

        /// <summary>
        /// 获取指定长度的随机字符
        /// </summary>
        /// <param name="len">字符长度</param>
        /// <returns>返回指定长度的随即字符串</returns>
        /// <remarks>
        /// len长度不能为0
        /// </remarks>
        /// <example>
        /// 以下示例一个获取4位长度的随即字符串
        /// <code>
        /// string r12 = HZ.Fun.GetRandomStr(4); 
        /// 
        /// </code>
        /// </example>
        public static string GetRandomStr(int len)
        {
            string src = "0123456789";
            int mode = src.Length;
            Random random = new Random(DateTime.Now.Millisecond);
            StringBuilder str = new StringBuilder(len);
            for (int i = 0; i < len; i++)
            {
                int pos = random.Next() % mode;
                str.Append(src[pos]);
            }
            return str.ToString();
        }

        #region 十六进制字符串与byte相互转换

        /// <summary>
        /// 把Hex字符串转换为字节组
        /// </summary>
        /// <param name="hexstr">待转换的16进制字符串</param>
        /// <returns>16进制字符串转换成功的字节数组</returns>
        /// <remarks>
        /// 传入的字符串必须只含0-9,A,B,C,D,E,F 大小写不分，并且长度为2的倍数。
        /// 比如0ACA
        /// </remarks>
        /// <example>
        /// 以下示例演示下该函数的使用
        /// <code>
        /// 
        /// string r3 = HZ.Fun.BytesToHex(new byte[] { 123, 12, 45, 5, 3, 1 });
        /// // 结果:"7B0C2D050301"
        /// byte[] r4 = HZ.Fun.HexToBytes(r3);
        /// // 结果:{ 123, 12, 45, 5, 3, 1 }
        /// </code>
        /// </example>
        /// <see cref="BytesToHex"/>
        public static byte[] HexToBytes(string hexstr)
        {
            try
            {
                byte[] buf = new byte[hexstr.Length / 2];
                for (int i = 0; i < hexstr.Length / 2; i++)
                {
                    buf[i] = byte.Parse(hexstr.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber);
                }
                return buf;
            }
            catch
            {
                throw;
            }
        }

        /// <summary>
        /// 将字节数组转换为Hex字符串
        /// </summary>
        /// <param name="buf">待转换的字节数组</param>
        /// <returns>转换后的16进制字符串</returns>
        /// <example>
        /// 以下示例演示下该函数的使用
        /// <code>
        /// 
        /// string r3 = HZ.Fun.BytesToHex(new byte[] { 123, 12, 45, 5, 3, 1 });
        /// // 结果:"7B0C2D050301"
        /// byte[] r4 = HZ.Fun.HexToBytes(r3);
        /// // 结果:{ 123, 12, 45, 5, 3, 1 }
        /// </code>
        /// </example>
        /// <see cref="HexToBytes"/>
        public static string BytesToHex(byte[] buf)
        {
            System.Text.StringBuilder sb = new StringBuilder();
            for (int i = 0; i < buf.Length; i++)
            {
                sb.Append(buf[i].ToString("X2"));
            }
            return sb.ToString();
        }

        #endregion

        #region 判断字符串是否符合数字要求

        /// <summary>
        /// 是否自然数
        /// </summary>
        /// <param name="s">用户输入的字符串</param>
        /// <returns>如果是正整数或0返回true，否则返回false</returns>
        /// <remarks>
        /// 若s是null，会返回异常。
        /// </remarks>
        /// <example>
        /// 举例
        /// <code>
        /// bool r = IsUInt("0"); // true
        /// r = IsUInt("100"); // true
        /// r = IsUInt("-1"); // false
        /// r = IsUInt("abc"); // false
        /// </code>
        /// </example>
        public static bool IsUInt(string s)
        {
            Regex r = new Regex(@"^\d+$");
            return r.IsMatch(s);
        }

        /// <summary>
        /// 是否非负小数
        /// </summary>
        /// <param name="s">用户输入的字符串</param>
        /// <returns>如果是非负小数返回true，否则返回false</returns>
        /// <remarks>
        /// 若s是null，会返回异常。
        /// </remarks>
        /// <example>
        /// 举例
        /// <code>
        /// bool r = IsUFloat("0.0"); // true
        /// r = IsUFloat("100.3"); // true
        /// r = IsUFloat("-1.2"); // false
        /// r = IsUFloat("abc"); // false
        /// </code>
        /// </example>
        public static bool IsUFloat(string s)
        {
            Regex r = new Regex(@"^(\d+)(\.\d+)?$");
            return r.IsMatch(s);
        }

        /// <summary>
        /// 是否整数
        /// </summary>
        /// <param name="s">用户输入的字符串</param>
        /// <returns>如果是是否整数返回true，否则返回false</returns>
        /// <remarks>
        /// 若s是null，会返回异常。
        /// </remarks>
        /// <example>
        /// 举例
        /// <code>
        /// bool r = IsInt("0"); // true
        /// r = IsInt("100"); // true
        /// r = IsInt("-1"); // true
        /// r = IsInt("abc"); // false
        /// </code>
        /// </example>
        public static bool IsInt(string s)
        {
            Regex r = new Regex(@"^-?\d+$");
            return r.IsMatch(s);
        }

        /// <summary>
        /// 是否为数字
        /// </summary>
        /// <param name="s">用户输入的字符串</param>
        /// <returns>如果是数字返回true，否则返回false</returns>
        /// <remarks>
        /// 若s是null，会返回异常。
        /// </remarks>
        /// <example>
        /// 举例
        /// <code>
        /// bool r = IsFloat("0.0"); // true
        /// r = IsFloat("100.3"); // true
        /// r = IsFloat("-1.2"); // true
        /// r = IsFloat("abc"); // false
        /// </code>
        /// </example>
        public static bool IsFloat(string s)
        {
            Regex r = new Regex(@"^(-?\d+)(\.\d+)?$");
            return r.IsMatch(s);
        }

        #endregion


        #region List相关


        public static bool Remove<T>(IList<T> List, T t) where T : IComparable<T>
        {
            foreach (var item in List)
            {
                if (item.CompareTo(t) == 0)
                {
                    List.Remove(item);
                    return true;

                }
            }
            return false;
        }

        /// <summary>
        /// 根据采购价获取限制零售价
        /// </summary>
        /// <param name="procurePrice"></param>
        /// <returns></returns>
        public static decimal? GetLimitPrice(decimal? procurePrice)
        {
            decimal? tempPrice;

            if (procurePrice > 500)
            {
                tempPrice = procurePrice + 75;
            }
            else if (procurePrice <= 500 && procurePrice > 0)
            {
                tempPrice = procurePrice * (decimal)1.15;
            }
            else
            {
                tempPrice = 0;
            }
            return tempPrice;
        }

        /// <summary>
        /// 根据限制零售价获取采购价
        /// </summary>
        /// <param name="limitPrice"></param>
        /// <returns></returns>
        public static decimal? GetProcurePrice(decimal? limitPrice)
        {
            decimal? tempPrice;
            if (limitPrice > 575)
            {
                tempPrice = limitPrice - 75;
            }
            else if (limitPrice <= 575 && limitPrice > 0)
            {
                tempPrice = limitPrice / (decimal)1.15;
            }
            else
            {
                tempPrice = 0;
            }
            return tempPrice;
        }

        #endregion

    }
}